package org.germinus.cardea.MuleServiceBundle.impl;


import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Random;
import java.util.Vector;

import ocp.context.Context;
import ocp.service.ContextConsumer;
import ocp.service.ContextService;


import org.mule.api.MuleException;
import org.mule.module.client.MuleClient;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;

public class StockConsumer implements ContextConsumer,Runnable {
	
	private static final Object SCREEN_MUTEX = new Object();

	private   String name;
	private   ContextService cs;
	private   ServiceRegistration sr;
	private   Thread thread;
	private   boolean running = false;
	
	private   MuleClient client;
	private   int umbral=0;
	
	String medicamentoContextId = null;
	
	private ContextBean cbean = ContextBean.getContextBean();

	//private DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
	SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
	
    /**
     * Constructor 
     * @param name nombre del modulo
     * @param bc BundleContex 
     */
	@SuppressWarnings("unchecked")
	public StockConsumer(  String name, BundleContext bc ) {
	      this.name = name;
	      this.thread = new Thread(this);
	      this.umbral=Integer.parseInt(bc.getProperty("org.esb.umbral"));
	      
	      try {
			this.client=new MuleClient();
	      } catch (MuleException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
	      }
	      
	   // Registra el servicio ContextConsumer
	        Hashtable props = new Hashtable();
	        props.put("id",  name ); 
	        if(bc!=null){
	        sr = bc.registerService( ContextConsumer.class.getName(), this , props );
	        }
	        
	        
	}
	
	/**
	  * Activa el thread
	  */
	public void start() {
	     running = true;
	     this.thread.start();
	}
	
	/**
	  * Para el thread y quita el registro del servicio
	  */
	public void stop() {
	      running = false;
	      try {
	          thread.join();
	      } catch (InterruptedException e) {
	          e.printStackTrace();
	      }
	      sr.unregister(); // opcional
	}
	
	/**
	  * Hilo del thread
	  */
	@SuppressWarnings("unchecked")
	public void run() {
				
		Random r = new Random();

        while (running) {
            
            try {
                Thread.sleep(3000);
            } catch (InterruptedException ex) {  }
        
            if( r.nextFloat() < 0.25  )  {  // con probabilidad del 25%
                
                // Si tenemos el interfaz de servicio y un id de contexto
                if( cs != null && medicamentoContextId!=null )  {
                    // leemos el contexto de OCP
                    Context context = cs.read( medicamentoContextId );
                    // lo mostramos por pantalla
                    //printContext(context,"(read)");
                }
            }
            
        }
	 }
	
	 /**
	   * Muestra los datos de un contexto por la consola
	   * @param context Contexto para mostrar
	   * @param type Fuente del contexto: read o notify
	   */
	 private void printContext(Context context,String title){
		 // Encapsulamos el contexto
	        MedicineContext contexto = new MedicineContext( context );
	        
	        synchronized (SCREEN_MUTEX) {
	            // mostramos el contexto con sus atributos por consola
	            contexto.printContext( "ESB: ", "Contexto " + title );
	            
	            // mostramos el número de contextos almacenados en el historico
	            int nHistorico = cs.getHistoricalContextLenght(context.getId());
	            System.out.println( " Elementos en el historico: " + nHistorico );
	            
	            // Si tenemos al menos 2 elementos los mostramos
	            if( nHistorico >=2 )  {
	            
	                // Obtenemos los últimos 2 contextos introducidos con el id de 'context'
	                Vector<Context> hContextos = cs.readHistoricalContextLast(context.getId(),2);
	                /*
	                    hContextos[0] es el contexto anterior
	                    hContextos[1] es el contexto actual
	                */ 
	                
	                /*
	                ContextoMedicamento cAnterior = new ContextoMedicamento( hContextos.elementAt(0) );
	                ContextoMedicamento cActual = new ContextoMedicamento( hContextos.elementAt(1) );
	                if(  !cAnterior.getLocalizacion().equals( cActual.getLocalizacion() )  )  {
	                    // la localización cambió
	                               System.out.println( "La Localizacion cambio " );
	                }
	                */
	                

	                // Mostramos los dos contextos
	                for( int i=0; i<2;i++)  {
	                    Context c = hContextos.elementAt(i);
	                    // encapsulamos el contexto c para que obtenga los attributos
	                    MedicineContext m = new MedicineContext( c );
	                    // mostramos por pantalla algunos datos
	                    System.out.println( "Contexto Historico: " + m.getContextId() 
	                                        + " localizacion: " + m.getLocalizacion() 
	                                        
	                                        );
	                    
	                }
	            }
	            System.out.println( " " );
	        }
	  }
	  /**
	    * Identificador para uso en log
	    * @return el identificador
	    */
	/*  private String getFullId() {
	       return new String( "DOCTOR[" + name +"]: ");
	  }*/
	  
	 /**
	    * Activa el ContextConsumer. Mensaje desde ocp para indicarnos que ya
	    * podemos hacer uso del servicio ContextService.
	    * @param cs Interfaz del servicio ContextService
	    * @see ContextService
	    */
	  public void activate(ContextService cs) {
	       this.cs = cs;
	    // Nos registramos a los contextos de tipo Medicamento
	        cs.registerToContextType( "Medicine", this );
	  }
	  
	  /**
	    * Desactiva el ContextConsumer. Mensaje desde ocp para indicarnos que el
	    * servicio ocp no esta disponible.
	    */
	  public void deactivate() {
	       cs = null;
	  }
	  
	  /**
	    * En caso de que el ContextConsumer se haya subscrito a los cambios de un
	    * contexto ocp nos notificará enviandonos el contexto actualizado.
	    * @param context Contexto que cambia
	    */
	  @SuppressWarnings("unchecked")
	public void notifyContextChange(Context context) {
			
			//MuleClient client;
			ArrayList params = new ArrayList();
			String message=null;
			String typeEvent=null;
			
			printContext(context,"(notify)");
			
			//Vector<Context> hContextos = cs.readHistoricalContextLast(context.getId(),2);
            /*
                hContextos[0] es el contexto anterior
                hContextos[1] es el contexto actual
            */ 
            
            //MedicineContext cAnterior = new MedicineContext( hContextos.elementAt(0) );
            //MedicineContext cActual = new MedicineContext( hContextos.elementAt(1) );
            
            //if(  !cAnterior.getLocalizacion().equals( cActual.getLocalizacion() )  )  {
                // la localización cambió
                System.out.println( "La Localizacion cambio " );
                
             // Encapsulamos el contexto
    	        MedicineContext contexto = new MedicineContext( context );
    			
    			params.add(2);
    			//params.add(context.getTagId());
    			params.add(contexto.getTagId());
    			//params.add(context.getType());
    			params.add(contexto.getName());
    			//params.add(context.getLocalization());
    			params.add(contexto.getLocalizacion());
    			   			
                if(contexto.getLocalizacion().equalsIgnoreCase("STOCK")){
                	typeEvent="1";
                }else{
                	typeEvent="2";
                }
                
              //Comprobamos el stock
    			//mediante cbean accedemos al RFID
                int stock=this.cbean.getStock(contexto.getName());
                
                if(stock>this.umbral){
                	if(contexto.getLocalizacion().equalsIgnoreCase("STOCK")){
                		message="El medicamento "+contexto.getTagId()+"/"+contexto.getName()+" ha sido expendido.";
                	}else{
                		message="El medicamento "+contexto.getTagId()+"/"+contexto.getName()+" ha sido almacenado en la farmacia.";
                	}
                	
                }else{
                	message="El stock de los medicamentos de tipo "+contexto.getName()+" esta por debajo del umbral ("
                			+stock+"/"+this.umbral+").";
                }
                
    			String parameters;
    			parameters="type="+typeEvent+"&tagId="+contexto.getTagId()+"&name="+
    						contexto.getName()+"&localization="+contexto.getLocalizacion()+
    						"&expDate="+df.format(contexto.getCaducityDate())+"&tagDate="+df.format(contexto.getRegisterDate())+
    						"&stock="+stock+"&message="+message;
    			
				Map messageProperties=new HashMap();
				messageProperties.put("message", params);
    			
    			try {
    				System.out.println("Stockconsumer: sending mule request");
    				//client = new MuleClient();
    				Activator.log("http://localhost:9080/CardeaServlet/CardeaManager?"+parameters);
    				
    				client.send("http://localhost:9080/CardeaServlet/CardeaManager?"+parameters, params, messageProperties);
    				Activator.log("Actualizacion del inventario de la farmacia: Baja de medicamento");
    				//client.send("http://localhost:8888/Prueba?"+parameters, new DefaultMuleMessage(params));
    				
    			} catch (MuleException e1) {
    				// TODO Auto-generated catch block
    				e1.printStackTrace();
    			}   
    			
    			Date fcad=contexto.getCaducityDate();
				Date actual= new Date();
				if(actual.after(fcad)){
					message="El medicamento "+contexto.getTagId()+"/"+contexto.getName()+" esta caducado y debe ser retirado.";
					parameters=null;
					parameters="type=3"+"&tagId="+contexto.getTagId()+"&name="+
					contexto.getName()+"&localization="+contexto.getLocalizacion()+
					"&expDate="+df.format(contexto.getCaducityDate())+"&tagDate="+df.format(contexto.getRegisterDate());
					
					messageProperties=null;
					messageProperties=new HashMap();
    				messageProperties.put("message", params);
    				
    				try {
    					Activator.log("http://localhost:9080/CardeaServlet/CardeaManager?"+parameters);
						client.send("http://localhost:9080/CardeaServlet/CardeaManager?"+parameters, params, messageProperties);
						Activator.log("Alarma caducidad: Medicamento caducado");
					} catch (MuleException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				
				if(stock<=umbral){
					//Enviamos a SIP un mensaje
					cbean.sendMessage(message);
				}
                           
            //}	
			
	  }
	  /**
	    * ocp nos notifica de los contextos nuevos creados en el sistema
	    * @param context Contexto nuevo introducido en ocp
	    */
	  @SuppressWarnings("unchecked")
	public void notifyNewContext(Context context) {

			// si no es de tipo Medicamento ignoralo
	        if( !context.getType().equals("Medicine") ) return;
	        
	        String message=null;
	        String typeEvent=null;
	        
	        printContext(context,"(notifyNewContext)");
	        
	        MedicineContext contexto = new MedicineContext( context );
	        
	        int stock=this.cbean.getStock(contexto.getName());
            
            if(stock>this.umbral){
            	if(contexto.getLocalizacion().equalsIgnoreCase("STOCK")){
            		message="El medicamento "+contexto.getTagId()+"/"+contexto.getName()+" ha sido expendido.";
            	}else{
            		message="El medicamento "+contexto.getTagId()+"/"+contexto.getName()+" ha sido almacenado en la farmacia.";
            	}
            }else{
            	message="El stock de los medicamentos de tipo "+contexto.getName()+" esta por debajo del umbral ("
            			+stock+"/"+this.umbral+").";
            }
			
			ArrayList params = new ArrayList();
			params.add(1);
			//params.add(context.getTagId());
			params.add(contexto.getTagId());
			//params.add(context.getType());
			params.add(contexto.getName());
			//params.add(context.getLocalization());
			params.add(contexto.getLocalizacion());
			//params.add(df.format(context.getCaducity()));
			params.add(df.format(contexto.getCaducityDate()));
			
			if(contexto.getLocalizacion().equalsIgnoreCase("STOCK")){
            	typeEvent="1";
            }else{
            	typeEvent="2";
            }
			
			String parameters;
			parameters="type="+typeEvent+"&tagId="+contexto.getTagId()+"&name="+
						contexto.getName()+"&localization="+contexto.getLocalizacion()+
						"&expDate="+df.format(contexto.getCaducityDate())+"&tagDate="+df.format(contexto.getRegisterDate())+
						"&stock="+stock+"&message="+message;
			
			Map messageProperties=new HashMap();
			messageProperties.put("message", params);
			
			try {
				System.out.println("Stockconsumer: sending mule request");
				//client = new MuleClient();
				Activator.log("http://localhost:9080/CardeaServlet/CardeaManager?"+parameters);
				client.send("http://localhost:9080/CardeaServlet/CardeaManager?"+parameters, params, messageProperties);
				Activator.log("Actualizacion del inventario de la farmacia: Alta de medicamento");
				//client.send("http://localhost:8888/Prueba?"+parameters, new DefaultMuleMessage(params));
				
			} catch (MuleException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			
			Date fcad=contexto.getCaducityDate();
			Date actual= new Date();
			if(actual.after(fcad)){
				message="El medicamento "+contexto.getTagId()+"/"+contexto.getName()+" esta caducado y debe ser retirado.";
				parameters=null;
				parameters="type=3"+"&tagId="+contexto.getTagId()+"&name="+
				contexto.getName()+"&localization="+contexto.getLocalizacion()+
				"&expDate="+contexto.getCaducityDate()+"&tagDate="+contexto.getRegisterDate();
				
				messageProperties=null;
				messageProperties=new HashMap();
				messageProperties.put("message", params);
				
				try {
					Activator.log("http://localhost:9080/CardeaServlet/CardeaManager?"+parameters);
					client.send("http://localhost:9080/CardeaServlet/CardeaManager?"+parameters, params, messageProperties);
					Activator.log("Alarma de caducidad: Medicamento caducado");
				} catch (MuleException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
			if(stock<=umbral){
				//Enviamos a SIP un mensaje
				cbean.sendMessage(message);
			}
	            
	        if( medicamentoContextId == null )  {  // si no tenemos un id 
	            // Guardamos el id del contexto para leerlo más tarde
	            medicamentoContextId = new String( context.getId() );
	        }
	        
			
	  }
	  
		/**
	    * Obtiene el identificador del ContextConsumer.
	    * @return el identificador
	    */
	  public String getId() {
	       return name;
	  }
 }
